#ifndef _HEAD_H_
#define _HEAD_H_

#include "queue.h"
#include "log.h"
#include "error_check.h"

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <signal.h>
#include <math.h>
#include <time.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
#include <ctype.h>
#include <pwd.h>
#include <grp.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <mysql/mysql.h>
#include <syslog.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/select.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/epoll.h>
#include <sys/sendfile.h>

//调用孔令阳的数据库接口的参数
//使用sql官方函数的参数请写入配置文件
#define MYSQL_HOST    "localhost"//本地链接
#define MYSQL_USER    "root"//登录数据库的用户名
#define MYSQL_PASSWD  "Zs123456!"//登录密码
#define DB_NAME "project1" //数据库名


//页偏移量
#define PAGE_OFFSET 4096
//一次接收字节大小
#define RECV_SIZE 1024

typedef struct pool_s {

    // 用来保存线程id
    pthread_t *list;
    // 用来记录线程池中线程个数
    int num;

    // 任务队列: 存net_fd
    queue_t queue;

    // 锁和条件变量
    pthread_mutex_t lock;
    pthread_mutex_t sql_lock;
    pthread_cond_t cond;

    // 退出标记位: 0正常, 1退出
    int exitFlag;

} pool_t;

typedef struct {
    //客户端视角的路径
    char path[1024];
    int path_tail;

    //用户名（id表示）
    char username[256];
    char password[1024];

    //命令编号
    int command_num;
    //存放客户端发来的命令
    char command_str_goto[1024];
    //存放要发回客户端的结果
    char command_str_return[1024];

    //一些标记
    int flag;

    //token
    char token[2048];
} path_t, user_info;

typedef struct train_s {
    int len;
    char buf[1024];
}train_t;

typedef struct SQL_STATUS{
    char query[4096];
    MYSQL_RES *result;
    MYSQL_ROW row;
}sql_t;


// 初始化信息
// 按照指定个数启动线程, 启动
int initPool(pool_t *pool, int num);

// 初始化socket: 设置端口ip, 监听
int initSocket(int *socket_fd, char *ip, char *port);

// 把文件描述符放入epoll监听
int addEpoll(int epoll_fd, int fd);

// 子线程的入口函数
void * threadMain(void *p);

// 给指定客户端传文件: 根据net_fd
int sendFile(int net_fd, char *path, MYSQL *conn, user_info info);
int recvFile(int net_fd, char *path, MYSQL *conn, user_info info);
void md5(char *file_name, char *md5_num);
bool sql_select(MYSQL *conn, char *sql_statement, sql_t *select_result);
bool sql_insert(MYSQL *conn, char *sql_statement, sql_t *insert_result);
bool sql_update(MYSQL *conn, char *sql_statement, sql_t *update_result);

//读取配置文件信息
int getparameter(char *key, char *value);

//ls指令
//char *fun_ls(char *path);
//rm指令
//int fun_rm(char *path, char *file_name);

bool file_exist(char *path, char *file_name);
//cd指令
int fun_cd(MYSQL *mysql,char *user_id,char *path,char *curr_path, pool_t *pool);
//int changeDir(path_t *dir,char *path,int length);
//mkdir指令
//int fun_mkdir(char *path, char *file_name);

//登录处理
void userLogin(int net_fd, user_info *info, MYSQL *conn, pool_t *pool);
void userRegister(int net_fd, user_info *info, MYSQL *conn, pool_t *pool);

//train发送数据
void sendCommand(int net_fd, char *path);

void sql_fun(MYSQL *database, sql_t *sql);

//ls指令
char *fun_ls_by_sql(MYSQL *database, user_info *info, train_t *train);

//mkdir指令
int fun_mkdir_by_sql(MYSQL *database, user_info *info);

//rm指令
int fun_rm_by_sql(MYSQL *database, user_info *info);


void recvInfoStruct(int net_fd, user_info *info);
void sendInfoStruct(int net_fd, user_info *info);
MYSQL *initSql(pool_t *pool);
char* getSalt(train_t *train);
#endif
